package edu.ccut.saturn.component.impl;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import edu.ccut.saturn.component.IDataInfo;
import edu.ccut.saturn.component.IDataItem;
import edu.ccut.saturn.component.ISaturnDataSqlInfo;
import edu.ccut.saturn.component.loader.SaturnDataLoader;
import edu.ccut.saturn.component.xml.ISaturnElement;
import edu.ccut.saturn.component.xml.SaturnElement;

public class SaturnDataInfo implements IDataInfo {

	private LinkedHashMap<String, IDataItem> dataItems;

	private String space;

	private String type;

	private String connectionName;

	private String sqlStr;

	private String description;

	private Map<String, ISaturnDataSqlInfo> sqlMap;

	private String dbType = IDataInfo.DATABASE_DRIVER_TYPE_ORACLE;

	public SaturnDataInfo(String connectionName, String sqlStr,
			String description, String space, String type, String dbType) {

		this.connectionName = connectionName;
		this.sqlStr = sqlStr;
		this.description = description;
		this.dataItems = new LinkedHashMap<String, IDataItem>();
		this.sqlMap = new HashMap<String, ISaturnDataSqlInfo>();
		this.space = space;
		this.type = type;

		if (dbType != null && !"".equals(dbType)) {
			this.dbType = dbType;
		}
	}

	/**
	 * add Data Item Note: if dataItem have column alias name, the key is column
	 * alias else dataItem's key is it's name.
	 */
	public void addDataItem(IDataItem dataItem) {
		String columnAlias = dataItem.getColumnAlias();

		if (columnAlias != null && !columnAlias.trim().equals("")) {
			this.dataItems.put(columnAlias, dataItem);

		} else {
			this.dataItems.put(dataItem.getName(), dataItem);
		}
	}

	public IDataItem getDataItem(String name) {
		return this.dataItems.get(name);
	}

	public String getSpace() {
		return space;
	}

	public void setSpace(String space) {
		this.space = space;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public Set<String> keySet() {
		return this.dataItems.keySet();
	}

	public Collection<IDataItem> values() {
		return this.dataItems.values();
	}

	protected Map<String, IDataItem> getDataItemMap() {
		return this.dataItems;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((type == null) ? 0 : type.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {

		if (this == obj) {
			return true;
		}

		if (obj == null) {
			return false;
		}

		if (getClass() != obj.getClass()) {
			return false;
		}

		final SaturnDataInfo other = (SaturnDataInfo) obj;

		if (type == null) {

			if (other.type != null) {
				return false;
			}

		} else if (!type.equals(other.type)) {
			return false;
		}
		return true;
	}

	public void setConnectionName(String connectionName) {
		this.connectionName = connectionName;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getConnectionName() {
		return this.connectionName;
	}

	public String getDescription() {
		return this.description;
	}

	public String getSqlStr() {
		return this.sqlStr;
	}

	public String getDataFullKey() {
		return this.space + IDataInfo.KEY_SEPARATOR + this.type;
	}

	public void addSqlInfo(ISaturnDataSqlInfo sqlInfo) {
		String id = sqlInfo.getKey();

		if (id != null && !"".equals(id)) {

			if (!this.sqlMap.containsKey(id)) {
				this.sqlMap.put(id, sqlInfo);
			}
		}
	}

	// TODO:键值重复未处理
	public void addSqlInfosByMap(Map<String, ISaturnDataSqlInfo> sqlInfoMap) {
		this.sqlMap.putAll(sqlInfoMap);
	}

	// TODO:键值重复未处理
	public void addSqlInfosByList(List<ISaturnDataSqlInfo> sqlInfoList) {

	}

	public String getSqlById(String id, Map<String, Object> paramMap)
			throws Exception {

		if (this.sqlMap.get(id) != null || !"".equals(this.sqlMap.get(id))) {
			return this.sqlMap.get(id).getSql(paramMap);
		}
		return null;
	}

	public String getDBType() {
		return this.dbType;
	}

	public void setDBType(String dbType) {
		this.dbType = dbType;
	}

	public ISaturnElement toSaturnElement() {
		boolean isSqldata = hasSqlText();
		String rootElementName = null;

		if (isSqldata) {
			rootElementName = "sql-dataentity";

		} else {
			rootElementName = "saturn-data";
		}
		ISaturnElement saturnDataElement = new SaturnElement(rootElementName);
		ISaturnElement dataElement = new SaturnElement(
				SaturnDataLoader.KEY_SATURNDATA_DATA);

		dataElement.addAttribute(SaturnDataLoader.KEY_DATA_NAME, this.type);
		dataElement
				.addAttribute(SaturnDataLoader.KEY_DATA_NAMESPACE, this.space);

		dataElement.addAttribute(SaturnDataLoader.KEY_DATA_DBTYPE, this.dbType);

		ISaturnElement connectionNameElement = new SaturnElement(
				SaturnDataLoader.KEY_DATA_CONNECTIONNAME, this.connectionName);

		ISaturnElement descriptionElement = new SaturnElement(
				SaturnDataLoader.KEY_DATA_DESCRIPTION, this.description);

		ISaturnElement fieldsElement = new SaturnElement(
				SaturnDataLoader.KEY_SATURNDATA_FIELDS);

		if (this.dataItems != null) {

			for (String itemKey : this.dataItems.keySet()) {
				IDataItem dataItem = this.dataItems.get(itemKey);
				fieldsElement.addSubElement(dataItem.toSaturnElement());
			}
		}

		if (this.sqlMap != null && this.sqlMap.size() > 0) {
			ISaturnElement sqlsElement = new SaturnElement(
					SaturnDataLoader.KEY_SATURNDATA_SQLS);

			for (String sqlKey : this.sqlMap.keySet()) {
				sqlsElement.addSubElement(this.sqlMap.get(sqlKey)
						.toSaturnElement());
			}
			saturnDataElement.addSubElement(sqlsElement);
		}

		if (isSqldata) {
			ISaturnElement sqlTextElement = new SaturnElement(
					SaturnDataLoader.KEY_SQLDATA_SQLSTR, this.sqlStr);

			saturnDataElement.addSubElement(sqlTextElement);
		}
		saturnDataElement.addSubElement(dataElement);
		dataElement.addSubElement(connectionNameElement);
		dataElement.addSubElement(descriptionElement);
		dataElement.addSubElement(fieldsElement);
		
		return saturnDataElement;
	}

	public String toXmlStr() {
		return toSaturnElement().getXMLStr();
	}

	public boolean hasSqlText() {

		if (this.sqlStr != null && !"".equals(this.sqlStr)) {
			return true;
		}
		return false;
	}
}
